//
// Created by DELL on 2023/12/13.
//

#include <iostream>
#include "WglContext.h"

GLuint shader, vao, vbo;
constexpr GLfloat vert[] = { 0.0f, 0.5f,  -0.5f, -0.5f,   0.5f, -0.5f};
constexpr const char* vertShaderSrc = R"(
#version 430 core
layout(location=0) in vec2 pos;
layout(location=0) uniform float scale;
layout(location=1) uniform float rotate;
void main()
{
    vec2 v = pos * scale;
    vec2 v2;
    v2.x = v.x * cos(rotate) - v.y * sin(rotate);
    v2.y = v.x * sin(rotate) + v.y * cos(rotate);
	gl_Position = vec4(v2, 0.0, 1.0);
}
)";
constexpr const char* fragShaderSrc = R"(
#version 430 core
layout(location=2)  uniform vec4 color;
out vec4 outColor;
void main()
{
	outColor = color;
}
)";
constexpr float pi = 3.1415926f;

void draw(const std::shared_ptr<WglContext>& context)
{
    context->bind();
    glClearColor(0.3f, 0.5f, 0.6f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glUseProgram(shader);
    glUniform1f(0 , 1.0f);
    glUniform1f(1 , 0.0f);
    glUniform4f(2, 1.0f, 0.0f, 0.0f, 1.0f);
    glBindVertexArray(vao);
    glDrawArrays(GL_TRIANGLES, 0, 3);

    context->swapBuffer();
    context->unbind();
}

int main()
{
    std::cout << "OpenGL Lock" << std::endl;

    auto context = WglContext::create(800, 600);
    context->setSwapInterval(0); // 关闭垂直同步
    context->bind();
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vert), vert, GL_DYNAMIC_DRAW);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
    glEnableVertexAttribArray(0);

    shader = glCreateProgram();
    GLuint vertShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertShader, 1, &vertShaderSrc, nullptr);
    glCompileShader(vertShader);
    glAttachShader(shader, vertShader);
    GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragShader, 1, &fragShaderSrc, nullptr);
    glCompileShader(fragShader);
    glAttachShader(shader, fragShader);
    glLinkProgram(shader);
    glDeleteShader(vertShader);
    glDeleteShader(fragShader);
    context->unbind();

    context->setResizeCallback([context](int w, int h){
        context->bind();
        glViewport(0, 0, w, h);
        context->unbind();
        draw(context); // 更新画面
    });

    std::atomic_bool isRunning = true;

    std::thread renderThread([context, &isRunning](){
        while (isRunning)
        {
            draw(context);
            std::this_thread::sleep_for(std::chrono::milliseconds(10)); // 等待，否则主线程会卡
        }
    });

    auto start = std::chrono::steady_clock::now();
    while (context->update())
    {
        auto time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start).count();
        float rotate = float(time % 800000) / 2000.0f;

        context->bind();
        GLfloat vertices[sizeof(vert)/sizeof(GLfloat)] = {};
        for (int i = 0; i < sizeof(vert)/sizeof(GLfloat)/2; ++i)
        {
            int x = i * 2;
            int y = i * 2 + 1;
            vertices[x] = vert[x] * cos(rotate) - vert[y] * sin(rotate);
            vertices[y] = vert[x] * sin(rotate) + vert[y] * cos(rotate);
        }

        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
        context->unbind();
        std::this_thread::sleep_for(std::chrono::milliseconds(1)); // 放弃当前cpu，让渲染线程更流程
//        std::this_thread::yield(); // 放弃当前cpu，让渲染线程更流程
    }
    isRunning = false;
    renderThread.join();
    context.reset();


    return 0;
}

